﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.IO;
using System.Threading;
using System.IO.Compression;

namespace winpackman
{
    public partial class FRMapply : Form
    {
        public FRMapply()
        {
            InitializeComponent();
        }

        public Dictionary<int, int> installid = new Dictionary<int, int>();
        public winpackman_class main_class = new winpackman_class();
        WebClient client = new WebClient();
        public string statelabelD;
        public string statelabelI;
        string Downloading;
        bool cancel = false;
        bool error = false;

        private void FRMapply_Load(object sender, EventArgs e)
        {
            client.Headers.Add("user-agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E)");
            progressI.Maximum = main_class.Installlist.Count * 100;
            progressD.Maximum = main_class.Installlist.Count * 100;
            BGWinstall.RunWorkerAsync();
            BGWdownload.RunWorkerAsync();
            
        }

        private void BGWinstall_DoWork(object sender, DoWorkEventArgs e)
        {
            
            foreach (InstallSoftware app in main_class.Installlist.Values)
            {
                Software masterdata = main_class.Softwarelist[app.MemberOf];
                statelabelI = "Wait for downlaod";
                while ((app.Status != "Downloaded") && !cancel && (app.InstallPercentage != 1)) Thread.Sleep(10);
                if (!cancel && !main_class.debug.downloadonly && (app.InstallPercentage != 1))
                {
                    app.Status = "Installing";
                    statelabelI = "Install " + app.Name;
                    switch (Path.GetExtension("Cache/" + app.install.Filename))
                    {
                        case ".msi":
                            process1.StartInfo.WorkingDirectory = "Cache/";
                            process1.StartInfo.FileName = "msiexec";
                            process1.StartInfo.Arguments = "/i " + app.install.Filename + " " + app.install.Arguments;
                            process1.Start();
                            process1.WaitForExit();
                            break;
                        case ".zip":
                            string tempdir = main_class.RandomString(8, true);
                            
                            ZipStorer zip = ZipStorer.Open("Cache/" + app.install.Filename, FileAccess.Read);
                            foreach (ZipStorer.ZipFileEntry entry in zip.ReadCentralDir())
                            {
                                zip.ExtractFile(entry, "Cache/" + tempdir + "/" + entry.FilenameInZip);
                            }
                            zip.Close();
                            
                            String[] info = app.install.Arguments.Split("#".ToCharArray());
                            process1.StartInfo.WorkingDirectory = "";
                            process1.StartInfo.FileName = "Cache/" + tempdir + "/" + info[0];
                            process1.StartInfo.Arguments = info[1];
                            process1.Start();
                            process1.WaitForExit();
                            Directory.Delete("Cache/" + tempdir, true);
                            break;
                        default:
                            process1.StartInfo.WorkingDirectory = "";
                            process1.StartInfo.FileName = "Cache/" + app.install.Filename;
                            process1.StartInfo.Arguments = app.install.Arguments;
                            process1.Start();
                            process1.WaitForExit();
                            break;
                    }
                    if (process1.ExitCode != 0)
                    {
                        switch (process1.ExitCode)
                        {
                            case 3010:
                                app.Status = "Error: restart required";
                                break;
                            default:
                                app.Status = "Error: " + process1.ExitCode;
                                break;
                        }
                        error = true;
                    }
                    else app.Status = "Done";
                    app.InstallPercentage = 100;
                    if (main_class.config.clearcache || (app.install.MD5 == ""))
                    {
                        try { File.Delete("Cache/" + app.install.Filename); }
                        catch { }
                    }
                }
                else app.Status = "Cancel";
            }
            statelabelI = "All installations completed";
            
        }

        private void BTNclose_Click(object sender, EventArgs e)
        {
            if (BTNclose.Text == "Close")
            {
                Close();
            }
            else
            {
                DialogResult result = MessageBox.Show(
                    "Do you want to cancel installation?",
                    "Cancel",
                    MessageBoxButtons.YesNo,
                    MessageBoxIcon.Question);
                if (result == System.Windows.Forms.DialogResult.Yes)
                {
                    cancel = true;
                    if (client.IsBusy)
                    {
                        client.CancelAsync();
                        while (client.IsBusy) { }
                        if (File.Exists("Cache/" +  Downloading)) File.Delete("Cache/" +  Downloading);
                    }
                    try { process1.Kill(); }
                    catch { }
                }
            }
        }

        private void BGWdownload_DoWork(object sender, DoWorkEventArgs e)
        {
            client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(client_DownloadProgressChanged);
            foreach (InstallSoftware app in main_class.Installlist.Values)
            {
                if (!cancel)
                {
                Download:
                    if (!File.Exists("Cache/" + app.install.Filename) || main_class.config.clearcache)
                    {
                        app.DownloadPercentage = 0;
                        statelabelD = "Download " + app.install.Filename;
                        app.Status = "Downloading";
                        Downloading = app.install.Filename;
                        client.DownloadFileAsync(new Uri(app.install.URL), "Cache/" + app.install.Filename);
                        while (client.IsBusy && !cancel) Thread.Sleep(10);
                    }
                    if (!cancel)
                    {
                        if (app.install.MD5 != "" || main_class.debug.md5out)
                        {
                            string MD5 = main_class.GetMD5HashFromFile("Cache/" + app.install.Filename);
                            if (String.Compare(MD5, app.install.MD5, true) != 0)
                            {
                                DialogResult result = MessageBox.Show("Error: MD5 checksum", "Error", MessageBoxButtons.AbortRetryIgnore, MessageBoxIcon.Error);
                                if (result == DialogResult.Abort)
                                {
                                    app.InstallPercentage = 1;
                                }
                                if (result == DialogResult.Retry)
                                {
                                    File.Delete("Cache/" + app.install.Filename);
                                    goto Download;
                                }

                            }
                            if (main_class.debug.md5out)
                            {
                                StreamWriter sw = new StreamWriter("MD5.txt", true);
                                sw.WriteLine(app.install.Filename + ";" + MD5);
                                sw.Close();
                            }
                        }
                    
                    }
                        
                    app.DownloadPercentage = 100;
                    app.Status = "Downloaded";
                }
                if (cancel) app.Status = "Cancel";
            }
            statelabelD = "All downloads complete";
            
        }

        private void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
        {
            
            foreach (InstallSoftware app in main_class.Installlist.Values)
            {
                if (app.install.Filename == Downloading)
                {
                    app.DownloadPercentage = e.ProgressPercentage;
                }
            }
            
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            if (LSTdetails.Items.Count != main_class.Installlist.Count)
            {
                LSTdetails.Items.Clear();
                installid.Clear();
                int count = 0;
                foreach (int key in main_class.Installlist.Keys)
                {
                    InstallSoftware app = main_class.Installlist[key];
                    LSTdetails.Items.Add(app.Name).SubItems.Add(app.Status);
                    installid.Add(key, count);
                    count++;
                }
            }

            int downloadPercentage = 0;
            int installPercentage = 0;
            foreach (int key in main_class.Installlist.Keys)
            {
                InstallSoftware app = main_class.Installlist[key];
                if (LSTdetails.Items[installid[key]].SubItems[1].Text != app.Status)
                {
                    if (app.Status.Contains("Error"))
                    {
                        LSTdetails.Items[installid[key]].BackColor = Color.Red;
                        LSTdetails.Items[installid[key]].ForeColor = Color.White;
                    }
                    if (app.Status == "Cancel")
                        LSTdetails.Items[installid[key]].BackColor = Color.Yellow;
                    LSTdetails.Items[installid[key]].SubItems[1].Text = app.Status;
                }
                downloadPercentage += app.DownloadPercentage;
                installPercentage += app.InstallPercentage;
            }
            if (progressD.Value != downloadPercentage) progressD.Value = downloadPercentage;
            if (progressI.Value != installPercentage) progressI.Value = installPercentage;
            
            if (statusD.Text != statelabelD) statusD.Text = statelabelD;
            if (statusI.Text != statelabelI) statusI.Text = statelabelI;           
        }

        private void BGWinstall_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (cancel)
            {
                statelabelI = "Cancel";
                statelabelD = "Cancel";
            }
            BTNclose.Text = "Close";
            progressI.Value = progressI.Maximum;
            if (!cancel)
            {
                if (!error)
                {
                    MessageBox.Show("All operation completed", "Done", MessageBoxButtons.OK, MessageBoxIcon.Information);
                }
                else
                {
                    MessageBox.Show("All operation completed, only a few errors", "Done", MessageBoxButtons.OK, MessageBoxIcon.Information);
                }
            }
        }

    }
}
